home *** CD-ROM | disk | FTP | other *** search
/ SGI Freeware 2002 November / SGI Freeware 2002 November - Disc 2.iso / dist / fw_glimpse.idb / usr / freeware / src / glimpse-3.0 / compress / hash.c.z / hash.c
C/C++ Source or Header  |  1997-09-09  |  17KB  |  638 lines

  1. /* Copyright (c) 1994 Burra Gopal, Udi Manber.  All Rights Reserved. */
  2.  
  3. /*
  4.  * hash.c:    Hash table manipulation routines. Can be used to compute
  5.  *        the dictionary as well as compress files.
  6.  */
  7.  
  8. #include "defs.h"
  9.  
  10. int next_free_hash = 0;
  11. hash_entry *free_hash = NULL; /*[DEF_MAX_WORDS]; */
  12.  
  13. int next_free_str = 0;
  14. char *free_str = NULL; /*[DEF_MAX_WORDS * AVG_WORD_LEN]; */
  15.  
  16. extern int usemalloc;
  17.  
  18. /* -----------------------------------------------------------------
  19. input: a word (a string of ascii character terminated by NULL)
  20. output: a hash_value of the input word.
  21. hash function: if the word has length <= 4
  22.         the hash value is just a concatenation of the last four bits
  23.         of the characters.
  24.         if the word has length > 4, then after the above operation,
  25.         the hash value is updated by adding each remaining character.
  26.         (and AND with the 16-bits mask).
  27. ---------------------------------------------------------------- */
  28. int
  29. thash64k(word, len)
  30. unsigned char *word;
  31. int len;
  32. {
  33.     unsigned int hash_value=0;
  34.     unsigned int mask_4=017;
  35.     unsigned int mask_16=0177777;
  36.     int i;
  37.  
  38.     if(len<=4) {
  39.         for(i=0; i<len; i++) {
  40.             hash_value = (hash_value << 4) | (word[i]&mask_4);
  41.             /* hash_value = hash_value  & mask_16; */
  42.         }
  43.     }
  44.     else {
  45.         for(i=0; i<4; i++) {
  46.             hash_value = (hash_value << 4) | (word[i]&mask_4);
  47.             /* hash_value = hash_value & mask_16;  */
  48.         }
  49.         for(i=4; i<len; i++)
  50.             hash_value = mask_16 & (hash_value + word[i]);
  51.     }
  52.     return(hash_value & mask_16);
  53. }
  54.  
  55. hash_entry *
  56. get_hash(hash_table, word, len, i)
  57.     hash_entry *hash_table[HASH_TABLE_SIZE];
  58.     unsigned char    *word;
  59.     int    len;
  60.     int    *i;
  61. {
  62.     hash_entry *e;
  63.  
  64.     *i = thash64k(word, len);
  65.     e = hash_table[*i];
  66.     while(e != NULL) {
  67.         if (!strcmp(e->word, (char *)word)) break;
  68.         else e = e->next;
  69.     }
  70.     return e;
  71. }
  72.  
  73. /*
  74.  * Assigns either the freq or the offset to the hash-entry. The kind of
  75.  * information in the entry depends on the caller. Advice: different
  76.  * hash-tables must be used to store information gathered during
  77.  * the build operation and the compress operation by the appropriate
  78.  * module. This can be specified by passing -1's for offset/freq resply.
  79.  */
  80. hash_entry *
  81. insert_hash(hash_table, word, len, freq, offset)
  82.     hash_entry *hash_table[HASH_TABLE_SIZE];
  83.     unsigned char    *word;
  84.     int    len, freq, offset;
  85. {
  86.     int    i;
  87.     hash_entry *e;
  88.  
  89.     e = get_hash(hash_table, word, len, &i);
  90.  
  91.     if (e == NULL) {
  92.         hashalloc(e);
  93.         stralloc(e->word, len + 2);
  94.         strcpy(e->word, (char *)word);
  95.         e->val.offset = 0;
  96.         e->next = hash_table[i];
  97.         hash_table[i] = e;
  98.     }
  99.  
  100.     if ((offset == -1) && (freq != -1)) {
  101.         e->val.attribute.freq += freq;
  102.         /* e->val.attribute.index has to be accessed from outside this function */
  103.     }
  104.     else if ((offset != -1) && (freq == -1)) {
  105.         e->val.offset = offset;
  106.         /* used in building the string table from the dictionary */
  107.     }
  108.     else {
  109.         fprintf(stderr, "error in accessing hash-table [frequencies/offsets]. skipping...\n");
  110.         return (NULL);
  111.     }
  112.  
  113. #if    0
  114.     printf("%d %x\n", i, e);
  115. #endif    /*0*/
  116.     return e;
  117. }
  118.  
  119. /*
  120.  * HASHFILE format: the hash-file is a sequence of "'\0' hash-index word-index word-name"
  121.  * The '\0' is there to indicate that this is not a padded line. Padded lines simply have
  122.  * a '\n' as the first character (words don't have '\0' or '\n'). The hash and word indices
  123.  * are 2 unsigned short integers in binary, MSB first. The word name therefore starts from the
  124.  * 5th character and continues until a '\0' or '\n' is encountered. The total size of the
  125.  * hash-table is therefore (|avgwordlen|+5)*numwords = appx 12 * 50000 = .6MB.
  126.  * Note that there can be multiple lines with the same hash-index.
  127.  */
  128.  
  129. /* used when computing compress's dictionary */
  130. int
  131. dump_hash(hash_table, HASHFILE)
  132.     hash_entry *hash_table[HASH_TABLE_SIZE];
  133.     unsigned char    *HASHFILE;
  134. {
  135.     int    i;
  136.     FILE    *hashfp;
  137.     int    wordindex;
  138.     hash_entry *e, *t;
  139.  
  140.     if ((hashfp = fopen((char *)HASHFILE, "w")) == NULL) {
  141.         fprintf(stderr, "cannot open for writing: %s\n", HASHFILE);
  142.         return 0;
  143.     }
  144.  
  145.     /* We have a guarantee that the wordindex + 1 cannot exceed MAX_WORDS */
  146.     wordindex = 0;
  147.     for(i=0; i<HASH_TABLE_SIZE; i++) {
  148.         e = hash_table[i];
  149.         while (e != NULL) {
  150.             fprintf(hashfp, "%d %d %s\n", i, wordindex, e->word);
  151.             t = e->next;
  152.             strfree(e->word);
  153.             hashfree(e);
  154.             e = t;
  155.             wordindex ++;
  156.         }
  157.     }
  158.  
  159.     fclose(hashfp);
  160.     return wordindex;
  161. }
  162.  
  163. /*
  164.  * These are routines that operate on hash-tables of 4K size (used in tbuild.c)
  165.  */
  166.  
  167. /* crazy hash function that operates on 4K hashtables */
  168. thash4k(word, len)
  169.     char     *word;
  170.     int    len;
  171. {
  172.     unsigned int hash_value=0;
  173.     unsigned int mask_3=07;
  174.     unsigned int mask_12=07777;
  175.     int i;
  176.  
  177. #if    0
  178.     /* discard prefix = the directory name */
  179.     if (len<=1) return 0;
  180.     i = len-1;
  181.     while(word[i] != '/') i--;
  182.     if ((i > 0) && (word[i] == '/')) {
  183.     word = &word[i+1];
  184.     len = strlen(word);
  185.     }
  186. #endif    /*0*/
  187.  
  188.     if(len<=4) {
  189.     for(i=0; i<len; i++) {
  190.                hash_value = (hash_value << 3) | (word[i]&mask_3);
  191.     }
  192.     }
  193.     else {
  194.     for(i=0; i<4; i++) {
  195.                hash_value = (hash_value << 3) | (word[i]&mask_3);
  196.     }
  197.     for(i=4; i<len; i++) 
  198.         hash_value = mask_12 & (hash_value + word[i]);
  199.     }
  200.     return(hash_value & mask_12);
  201. }
  202.  
  203. hash_entry *
  204. get_small_hash(hash_table, word, len, i)
  205.     hash_entry *hash_table[SMALL_HASH_TABLE_SIZE];
  206.     unsigned char    *word;
  207.     int    len;
  208.     int    *i;
  209. {
  210.     hash_entry *e;
  211.  
  212.     *i = thash4k(word, len);
  213.     e = hash_table[*i];
  214.     while(e != NULL) {
  215.         if (!strcmp(e->word, (char *)word)) break;
  216.         else e = e->next;
  217.     }
  218.     return e;
  219. }
  220.  
  221. hash_entry *
  222. insert_small_hash(hash_table, word, len, freq, offset)
  223.     hash_entry *hash_table[SMALL_HASH_TABLE_SIZE];
  224.     unsigned char    *word;
  225.     int    len, freq, offset;
  226. {
  227.     int    i;
  228.     hash_entry *e;
  229.  
  230.     e = get_small_hash(hash_table, word, len, &i);
  231.  
  232.     if (e == NULL) {
  233.         hashalloc(e);
  234.         stralloc(e->word, len + 2);
  235.         strcpy(e->word, (char *)word);
  236.         e->val.offset = 0;
  237.         e->next = hash_table[i];
  238.         hash_table[i] = e;
  239.     }
  240.  
  241.     if ((offset == -1) && (freq != -1)) {
  242.         e->val.attribute.freq += freq;
  243.         /* e->val.attribute.index has to be accessed from outside this function */
  244.     }
  245.     else if ((offset != -1) && (freq == -1)) {
  246.         e->val.offset = offset;
  247.         /* used in building the string table from the dictionary */
  248.     }
  249.     else {
  250.         fprintf(stderr, "error in accessing hash-table [frequencies/offsets]. skipping...\n");
  251.         return (NULL);
  252.     }
  253.  
  254. #if    0
  255.     printf("%d %x\n", i, e);
  256. #endif    /*0*/
  257.     return e;
  258. }
  259.  
  260. int
  261. dump_small_hash(hash_table, HASHFILE)
  262.     hash_entry *hash_table[SMALL_HASH_TABLE_SIZE];
  263.     unsigned char    *HASHFILE;
  264. {
  265.     int    i;
  266.     FILE    *hashfp;
  267.     int    wordindex;
  268.     hash_entry *e, *t;
  269.  
  270.     if ((hashfp = fopen((char *)HASHFILE, "w")) == NULL) {
  271.         fprintf(stderr, "cannot open for writing: %s\n", HASHFILE);
  272.         return 0;
  273.     }
  274.  
  275.     /* We have a guarantee that the wordindex + 1 cannot exceed MAX_WORDS */
  276.     wordindex = 0;
  277.     for(i=0; i<SMALL_HASH_TABLE_SIZE; i++) {
  278.         e = hash_table[i];
  279.         while (e != NULL) {
  280.             fprintf(hashfp, "%d %d %s\n", thash64k(e->word, strlen(e->word)), wordindex, e->word);    /* must look like I used 64K table */
  281.             t = e->next;
  282.             strfree(e->word);
  283.             hashfree(e);
  284.             e = t;
  285.             wordindex ++;
  286.         }
  287.     }
  288.  
  289.     fclose(hashfp);
  290.     return wordindex;
  291. }
  292.  
  293. /*
  294.  * These are again routines that operate on big (64k) hash-tables
  295.  */
  296.  
  297. /* used only during debugging to see if output = input */
  298. int
  299. dump_hash_debug(hash_table, HASHFILE)
  300.     hash_entry *hash_table[HASH_TABLE_SIZE];
  301.     unsigned char    *HASHFILE;
  302. {
  303.     int    i;
  304.     FILE    *hashfp;
  305.     hash_entry *e;
  306.  
  307.     if ((hashfp = fopen((char *)HASHFILE, "w")) == NULL) {
  308.         fprintf(stderr, "cannot open for writing: %s\n", HASHFILE);
  309.         return 0;
  310.     }
  311.  
  312.     /* We have a guarantee that the wordindex + 1 cannot exceed MAX_WORDS */
  313.     for(i=0; i<HASH_TABLE_SIZE; i++) {
  314.         e = hash_table[i];
  315.         while (e != NULL) {
  316.             fprintf(hashfp, "%d %d %d %s\n", i, e->val.attribute.freq, e->val.attribute.index, e->word);
  317.             e = e->next;
  318.         }
  319.     }
  320.  
  321.     fclose(hashfp);
  322.     return 1;
  323. }
  324.  
  325. /*
  326.  * VERY particular to the format of the hash-table file:
  327.  * -- does an fscanf+2atoi's+strlen all in one scan.
  328.  * Returns 0 if you are in padded are, -1 on EOF, else ~.
  329.  */
  330. int
  331. myhashread(fp, pint1, pint2, str, plen)
  332.     FILE    *fp;
  333.     int    *pint1;
  334.     int    *pint2;
  335.     char    *str;
  336.     int    *plen;
  337. {
  338.     int    numread;
  339.     int    int1, int2;
  340.     int    c;
  341.  
  342.     if((int1 = getc(fp)) == '\n') return 0;    /* padded area */
  343.     if(int1 != 0) return -1;        /* formatting error! */
  344.     if ((int1 = getc(fp)) == EOF) return -1;
  345.     if ((int2 = getc(fp)) == EOF) return -1;
  346.     *pint1 = (int1 << 8) | int2;        /* hashindex */
  347.     if ((int1 = getc(fp)) == EOF) return -1;
  348.     if ((int2 = getc(fp)) == EOF) return -1;
  349.     *pint2 = (int1 << 8) | int2;        /* wordindex */
  350.  
  351.     numread = 5;
  352.     *plen = 0;                /* wordname */
  353.     while((c = getc(fp)) != EOF) {
  354.         if ( (c == '\0') || (c == '\n') ){
  355.             ungetc(c, fp);
  356.             str[*plen] = '\0';
  357.             return numread;
  358.         }
  359.         str[(*plen)++] = c;
  360.         numread ++;
  361.         if (numread >= MAX_NAME_LEN) {
  362.             str[*plen - 1] = '\0';
  363.             return numread;
  364.         }
  365.     }
  366.     return -1;
  367. }
  368.  
  369. int
  370. tbuild_hash(hash_table, hashfp, bytestoread)
  371.     hash_entry    *hash_table[HASH_TABLE_SIZE];
  372.     FILE        *hashfp;
  373.     int        bytestoread;
  374. {
  375.     int    hashindex;
  376.     int    wordindex;
  377.     int    numread = 0;
  378.     int    ret;
  379.     int    len;
  380.     char    *word;
  381.     char    dummybuf[MAX_WORD_BUF];
  382.     hash_entry *e;
  383.  
  384.     if (bytestoread == -1) {    /* read until end of file */
  385.         while (1)
  386.         {
  387.             if (usemalloc) word = dummybuf;
  388.             else {
  389.                 if (free_str == NULL) free_str = (char *)malloc(AVG_WORD_LEN * DEF_MAX_WORDS);
  390.                 if (free_str == NULL) break;
  391.                 word = &free_str[next_free_str];
  392.             }
  393.             if ((ret = myhashread(hashfp, &hashindex, &wordindex, word, &len)) == 0) continue;
  394.             if (ret == -1) break;
  395.             if ((hashindex >= HASH_TABLE_SIZE) || (hashindex < 0)) continue;    /* ignore */
  396.             hashalloc(e);
  397.             if (usemalloc) {
  398.                 if ((word = (char *)malloc(len + 2)) == NULL) break;
  399.                 strcpy(word, dummybuf);
  400.             }
  401.             else next_free_str += len + 2;
  402.             e->word = word;
  403.             e->val.attribute.freq = 0;    /* just exists in compress's dict: not found in text-file yet! */
  404.             e->val.attribute.index = wordindex;
  405.             e->next = hash_table[hashindex];
  406.             hash_table[hashindex] = e;
  407. #if    0
  408.             printf("word=%s index=%d\n", word, wordindex);
  409. #endif    /*0*/
  410.         }
  411.     }
  412.     else {    /* read only a specified number of bytes */
  413.         while (bytestoread > numread)
  414.         {
  415.             if (usemalloc) word = dummybuf;
  416.             else {
  417.                 if (free_str == NULL) free_str = (char *)malloc(AVG_WORD_LEN * DEF_MAX_WORDS);
  418.                 if (free_str == NULL) break;
  419.                 word = &free_str[next_free_str];
  420.             }
  421.             if ((ret = myhashread(hashfp, &hashindex, &wordindex, word, &len)) <= 0) break;
  422.             if ((hashindex >= HASH_TABLE_SIZE) || (hashindex < 0)) continue;    /* ignore */
  423.             hashalloc(e);
  424.             if (usemalloc) {
  425.                 if ((word = (char *)malloc(len + 2)) == NULL) break;
  426.                 strcpy(word, dummybuf);
  427.             }
  428.             else next_free_str += len + 2;
  429.             e->word = word;
  430.             e->val.attribute.freq = 0;    /* just exists in compress's dict: not found in text-file yet! */
  431.             e->val.attribute.index = wordindex;
  432.             e->next = hash_table[hashindex];
  433.             hash_table[hashindex] = e;
  434.             wordindex ++;
  435.             numread += ret;
  436. #if    0
  437.             printf("%d %d %s\n", hashindex, wordindex, word);
  438. #endif    /*0*/
  439.         }
  440.     }
  441.  
  442.     return (wordindex + 1);    /* the highest indexed word + 1 */
  443. }
  444.  
  445. /*
  446.  * Interprets srcbuf as a series of words separated by newlines and looks
  447.  * for a complete occurrence of words in patbuf in it. If there IS an occurrence,
  448.  * it builds the hash-table for THAT page. The hashfp must start at the
  449.  * beginning on each call.
  450.  */
  451. int
  452. build_partial_hash(hash_table, hashfp, srcbuf, srclen, patbuf, patlen, blocksize, loaded_hash_table)
  453.     hash_entry *hash_table[HASH_TABLE_SIZE];
  454.     FILE    *hashfp;
  455.     unsigned char    *srcbuf;
  456.     int    srclen;
  457.     unsigned char    *patbuf;
  458.     int    patlen;
  459.     int    blocksize;
  460.     char    loaded_hash_table[HASH_FILE_BLOCKS];
  461. {
  462.     unsigned char    *srcpos;
  463.     unsigned char    *srcinit, *srcend, dest[MAX_NAME_LEN];
  464.     int    blockindex = 0;
  465.     int    i, initlen, endlen;
  466.     unsigned char    *strings[MAX_NAME_LEN];    /* maximum pattern length */
  467.     int    numstrings = 0;
  468.     int    inword = 0;
  469.  
  470.     /*
  471.      * Find all the relevant strings in the pattern.
  472.      */
  473.     i = 0;
  474.     while(i<patlen) {
  475.         if (isalnum(patbuf[i])) {
  476.             if (!inword) {
  477.                 strings[numstrings++] = &dest[i];
  478.                 inword = 1;
  479.             }
  480.             if (isupper(patbuf[i])) dest[i] = tolower(patbuf[i]);
  481.             else dest[i] = patbuf[i];
  482.         }
  483.         else {
  484.             dest[i] = '\0';    /* ignore that character */
  485.             inword = 0;
  486.         }
  487.         i++;
  488.     }
  489. #if    0
  490.     for (i=0; i<numstrings; i++) printf("word%d=%s\n", i, strings[i]);
  491.     getchar();
  492. #endif    /*0*/
  493.  
  494.     srcpos = srcbuf;
  495.     while (srcpos < (srcbuf + srclen)) {
  496.         srcinit = srcpos;
  497.         initlen = strlen((char *)srcinit);
  498.         srcend = srcinit + initlen + 1;
  499.         endlen = strlen((char *)srcend);
  500. #if    0
  501.         printf("%s -- %s\n", srcinit, srcend);
  502. #endif    /*0*/
  503.         for (i=0; i<numstrings; i++)
  504.             if ((strcmp((char *)strings[i], (char *)srcinit) >= 0) && (strcmp((char *)strings[i], (char *)srcend) <= 0)) goto include_page;
  505.         blockindex++;
  506.         srcpos += (initlen + endlen + 2);
  507.         continue;
  508.  
  509.     include_page:    /* Include it if any of the patterns fit within this range */
  510.         if (loaded_hash_table[blockindex++]) continue;
  511. #if    0
  512.         printf("build_partial_hash: hashing words in page# %d\n", blockindex);
  513. #endif    /*0*/
  514.         loaded_hash_table[blockindex - 1] = 1;
  515.         fseek(hashfp, (blockindex-1)*blocksize, 0);
  516.         tbuild_hash(hash_table, hashfp, blocksize);
  517.         srcpos += (initlen + endlen + 2);
  518.     }
  519.     return 0;
  520. }
  521.  
  522. pad_hash_file(filename, FILEBLOCKSIZE)
  523.     unsigned char *filename;
  524.     int FILEBLOCKSIZE;
  525. {
  526.     FILE    *outfp, *infp, *indexfp;
  527.     int    offset = 0, len;
  528.     unsigned char buf[MAX_NAME_LEN];
  529.     int    pid = getpid();
  530.     int    i;
  531.     unsigned char    word[MAX_NAME_LEN];
  532.     unsigned char    prev_word[MAX_NAME_LEN];
  533.     unsigned int    hashindex, wordindex;
  534.  
  535.     if ((infp = fopen((char *)filename, "r")) == NULL) {
  536.         fprintf(stderr, "cannot open for reading: %s\n", filename);
  537.         exit(2);
  538.     }
  539.     sprintf(buf, "%s.index", filename);
  540.     if ((indexfp = fopen(buf, "w")) == NULL) {
  541.         fprintf(stderr, "cannot open for writing: %s\n", buf);
  542.         fclose(infp);
  543.         exit(2);
  544.     }
  545.     sprintf(buf, "%s.%d", filename, pid);
  546.     if ((outfp = fopen(buf, "w")) == NULL) {
  547.         fprintf(stderr, "cannot open for writing: %s\n", buf);
  548.         fclose(infp);
  549.         fclose(indexfp);
  550.         exit(2);
  551.     }
  552.     if ((FILEBLOCKSIZE % MIN_BLOCKSIZE) != 0) {
  553.         fprintf(stderr, "invalid block size %d: changing to %d\n", FILEBLOCKSIZE, MIN_BLOCKSIZE);
  554.         FILEBLOCKSIZE = MIN_BLOCKSIZE;
  555.     }
  556.     fprintf(indexfp, "%d\n", FILEBLOCKSIZE);
  557.  
  558.     if ((char*)buf != fgets(buf, MAX_NAME_LEN, infp)) goto end_of_input;
  559.     len = strlen((char *)buf);
  560.  
  561.     sscanf(buf, "%d %d %s\n", &hashindex, &wordindex, word);
  562.     putc(0, outfp);
  563.     putc((hashindex & 0xff00)>>8, outfp);
  564.     putc((hashindex & 0x00ff), outfp);
  565.     putc((wordindex & 0xff00)>>8, outfp);
  566.     putc((wordindex & 0x00ff), outfp);
  567.     fprintf(outfp, "%s", word);
  568.  
  569.     buf[len-1] = '\0';            /* fgets gives you the newline too */
  570.         for (i=0; i< len; i++) if (isupper(buf[i])) buf[i] = tolower(buf[i]);
  571.     for (i=len-2; i>=0; i--) if (buf[i] == ' ') { i++; break; }
  572.     if (i < 0) i = 0;
  573.     strcpy((char *)prev_word, (char *)&buf[i]);
  574.  
  575.     fprintf(indexfp, "%s", &buf[i]);    /* the first word */
  576.     putc(0, indexfp);            /* null terminated */
  577.     offset += strlen((char *)word)+5;
  578.  
  579.      while(fgets(buf, MAX_NAME_LEN, infp) == (char *)buf) {
  580.         len = strlen((char *)buf);
  581.         if (offset + len > FILEBLOCKSIZE) {
  582.             /* Put the last char of the prev. page */
  583.             fprintf(indexfp, "%s", prev_word);
  584.             putc(0, indexfp);    /* null terminated */
  585.                 
  586.             for (i=0; i<FILEBLOCKSIZE-offset; i++)    /* fill up with so many newlines until the next block size */
  587.                 putc('\n', outfp);
  588.  
  589.  
  590.             sscanf(buf, "%d %d %s\n", &hashindex, &wordindex, word);
  591.             putc(0, outfp);
  592.             putc((hashindex & 0xff00)>>8, outfp);
  593.             putc((hashindex & 0x00ff), outfp);
  594.             putc((wordindex & 0xff00)>>8, outfp);
  595.             putc((wordindex & 0x00ff), outfp);
  596.             fprintf(outfp, "%s", word);
  597.  
  598.                         buf[len-1] = '\0';            /* fgets gives you the newline too */
  599.                         for (i=0; i< len; i++) if (isupper(buf[i])) buf[i] = tolower(buf[i]);
  600.                         for (i=len-2; i>=0; i--) if (buf[i] == ' ') { i++; break; }
  601.                         if (i < 0) i = 0;
  602.                         strcpy((char *)prev_word, (char *)&buf[i]);
  603.  
  604.             fprintf(indexfp, "%s", &buf[i]);    /* store the first word at each page */
  605.             putc(0, indexfp);            /* null terminated */
  606.             offset = 0;
  607.         }
  608.         else {
  609.             sscanf(buf, "%d %d %s\n", &hashindex, &wordindex, word);
  610.             putc(0, outfp);
  611.             putc((hashindex & 0xff00)>>8, outfp);
  612.             putc((hashindex & 0x00ff), outfp);
  613.             putc((wordindex & 0xff00)>>8, outfp);
  614.             putc((wordindex & 0x00ff), outfp);
  615.             fprintf(outfp, "%s", word);
  616.  
  617.                         buf[len-1] = '\0';            /* fgets gives you the newline too */
  618.                         for (i=0; i<len; i++) if (isupper(buf[i])) buf[i] = tolower(buf[i]);
  619.                         for (i=len-2; i>=0; i--) if (buf[i] == ' ') { i++; break; }
  620.                         if (i < 0) i = 0;
  621.                         strcpy((char *)prev_word, (char *)&buf[i]);
  622.         }
  623.         offset += strlen((char *)word)+5;
  624.     }
  625.     fprintf(indexfp, "%s", prev_word);
  626.     putc(0, indexfp);            /* null terminated */
  627.  
  628. end_of_input:
  629.     fclose(infp);
  630.     fflush(outfp);
  631.     fclose(outfp);
  632.     fflush(indexfp);
  633.     fclose(indexfp);
  634.     sprintf(buf, "mv %s.%d %s\n", filename, pid, filename);
  635.     system(buf);
  636. }
  637.  
  638.